home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
sortdir2.arc
/
SORTDIR2.ASM
< prev
next >
Wrap
Assembly Source File
|
1991-09-15
|
51KB
|
1,180 lines
PAGE 84,132
;-----------------------------------------------------------------------------|
; ---- ScanSoft(tm) SORTDIR (C)1991 Cornel Huth -- All Rights Reserved ---- |
;-----------------------------------------------------------------------------|
; program: SORTDIR.ASM |
; version: 1.02 COPYRIGHT 1991 Cornel Huth |
; by: Cornel Huth 6402 Ingram Rd/San Antonio, TX/78238 |
; date: 09-Sep-91 |
; function: sort current directory |
; caller: COMMAND |
; use: |
; |
; C>SD [options] * sort current directory by filename [options] |
; options: |
; SD /e * by ext.filename (default) |
; SD /n * by filename.ext |
; SD /h * help with anything other CLP |
;-----------------------------------------------------------------------------|
;NOTES: |
;Code requires DOS 3.2+ for IOCTL functions |
;Requires MASM 5.1 to assemble |
;Should work on any DOS machine since everything is DOS done |
;User documentation found, where else, in the User Documentation |
;LIMITATIONS: (some could be considered benifits) |
;Operates on current drive/current directory only |
;Will not sort entries prior to any hidden, system, or subdirectory entries |
;Root directory must lie in the first 64K sectors of the DOS drive(no problem)|
;FAT must be less than 64K (no problem) |
;Maximum of 1792 directory entries per subdirectory (seems like enough) |
;Sort source not included (how does that grab you?) |
;-----------------------------------------------------------------------------|
;Being a programmer I'm always deleting working files. I like to keep my subs |
;packed and files grouped by extension. 32MB+ parts made Norton DS unusable so|
;PCTools 4.22 had been used to sort subdirs on large DOS 3.31 parts. HOWEVER, |
;in writing this code (using PCT422 for direct disk access) I noticed PCT422 |
;becomes real flakey (try accessing, say, cluster# 18,000, or even 10,000)-- |
;--a real good reason to have a dir sort program written for large partitions.|
;One reason for this is that previous DOS versions had a total sector count |
;indicating the number of sectors on a drive. If it was 4086 or less then the |
;FAT used 12-bit entries, 4087 or more, 16-bit entries. In DOS versions that |
;allow large partitions, the total sector count is not large enough to express|
;sector counts above 64K. What these do then is set the regular total sector |
;count to 0 and in another location set a 32-bit entry to the total sectors. |
;What is probably happening is that programs unaware of the new DOS tactic is |
;checking for a total sector count less than 4087 (which it is on large parts)|
;and if so, assumes a 12-bit FAT! Some programs see the 0 for what it is, |
;somewhat, and indicate that the FAT scheme is unknown. |
;-----------------------------------------------------------------------------|
; NOTICE: NOTICE: NOTICE: NOTICE: NOTICE: NOTICE: NOTICE: NOTICE: NOTICE: |
;-----------------------------------------------------------------------------|
; >>>>>>>>>>>>>>>>> THIS SOURCE CODE IS *NOT* PUBLIC DOMAIN <<<<<<<<<<<<<<<<< |
;-----------------------------------------------------------------------------|
;I allow you to modify this source ONLY for your personal, non-commercial use |
;You may NOT distribute this source if altered in any way |
;You may NOT distribute any directory sorting program derived from this source|
;If you can't abide by these terms then don't use any of this code. |
;-----------------------------------------------------------------------------|
;C>masm sd.asm;
;C>link /cp:1 sd,sd.exe; (MUST LINK WITH /cp:1)
;-----------------------------------------------------------------------------|
;1.00-chh 2-Sep-91 Initial release
;1.01-chh 6-Sep-91 A1* Change entries-to-sort parm (CX) of Quiksort to position-
;of-last-sort-item since we're not starting sort (necessarily) at item 1
;1.02-chh 9-Sep-91 B0* Change stack to 1024 bytes from 512
;B1* Move DOS 1 ret setup to start of program for correct PSP segment push
;B2* Increase max directory entries to 1792 and correct too many clusters check
;since previous code check based on 1 sector/cluster
;B3* Change default sort order to ext.filename
;B4* Floppies will have byte F6h in the root directory from the format--need to
;explicitly check for the entry being unused (byte0=0) and not assume that
;if it is unused that all the bytes will be that way. Thanks K.B.
;-----------------------------------------------------------------------------|
WPTR EQU <WORD PTR>
BPTR EQU <BYTE PTR>
STDIN EQU 0
STDOUT EQU 1
STDERR EQU 2
MAXDIR EQU 1792 ;B2* max directory entries per subdir (1792=56K)
;(MAXDIR*32 should be evenly divisble by cluster size in bytes)
;for all cluster size from 512,1024,2048,4096,8192 the full
;1792 entries are available, 16K clusters can have 1536 avail
DeviceParms STRUC ;DEVICE PARMS STRUCTURE
dpSpecFunc db 1 DUP (?) ;special functions
dpDevType db 1 DUP (?) ;device type
dpDevAttr dw 1 DUP (?) ;device attribute
dpCylinders dw 1 DUP (?) ;number of cylinders
dpMediaType db 1 DUP (?) ;media type
;BPB follows
dpBytesSector dw 1 DUP (?) ;bytes per sector
dpSectorsClust db 1 DUP (?) ;sectors per cluster
dpResSectors dw 1 DUP (?) ;reserved sectors
dpFATs db 1 DUP (?) ;number of FATs
dpRootDirEnts dw 1 DUP (?) ;root directory entries
dpSectors dw 1 DUP (?) ;if 0 then > 32MB DOS drive, use dpHugeSectors
dpMedia db 1 DUP (?) ;media byte
dpFATsecs dw 1 DUP (?) ;sectors used by each FAT
dpSectorsTrack dw 1 DUP (?) ;sectors per track
dpHeads dw 1 DUP (?) ;heads
dpHiddenSecs dd 1 DUP (?) ;hidden sectors
dpHugeSectors dd 1 DUP (?) ;number of sectors if dpSectors=0
DeviceParms ENDS
rwBlock STRUC ;READ/WRITE TRACK ON LOGICAL DRIVE STRUCTURE
rwSpecFunc db 1 DUP (?)
rwHead dw 1 DUP (?)
rwCylinder dw 1 DUP (?)
rwFirstSector dw 1 DUP (?)
rwSectors dw 1 DUP (?)
rwBuffer dd 1 DUP (?)
rwBlock ENDS
DirEntry STRUC ;DIRECTORY ENTRY STRUCTURE
deName db 8 DUP (?)
deExtension db 3 DUP (?)
deAttributes db 1 DUP (?)
deReserved db 10 DUP (?)
deTime dw 1 DUP (?)
deDate dw 1 DUP (?)
deStartCluster dw 1 DUP (?)
deFileSize dd 1 DUP (?)
DirEntry ENDS
DOSSEG
.MODEL SMALL
.STACK 1024 ;B0* more stack for the expand sort buffer
.DATA? ;simplified segment directives use DGROUP offset
MajorV db 1 DUP (?) ;DOS version
MinorV db 1 DUP (?) ;-
INT24error dw 1 DUP (?) ;DOS fatal error
INT24seg dw 1 DUP (?) ;original INT24 vector
INT24off dw 1 DUP (?) ;-DOS restores on program exit
INT23seg dw 1 DUP (?) ;original INT23 vector
INT23off dw 1 DUP (?) ;-DOS restores on program exit
INT1Bseg dw 1 DUP (?) ;original INT1B vector
INT1Boff dw 1 DUP (?) ;-must be restored before exiting (BIOS vector)
INT00seg dw 1 DUP (?) ;original INT00 vector
INT00off dw 1 DUP (?) ;-must be restored before exiting (BIOS vector)
PSPseg dw 1 DUP (?) ;PSP segment at load time
SegBuffFAT dw 1 DUP (?) ;segment of buffer for FAT
SegBuffFAT2 dw 1 DUP (?) ;segment of buffer for FAT2
FATtype db 1 DUP (?) ;12 or 16 for FAT bit size
CurrDrive db 1 DUP (?) ;current DOS drive (default)
CurrDir db 64 DUP (?) ;current DOS directory
StartCluster dw 1 DUP (?) ;starting cluster of subdirectory
ClusterList dw MAXDIR/16/1 DUP (?) ;cluster link list (say, 112)
;(1792 entries/16 ent/sec/clust (1 sec/cluster))
ClusterListOF dw 1 DUP (?) ;end of link marker overflow
FATsector dw 1 DUP (?) ;logical DOS sector of first FAT
ROOTsector dw 1 DUP (?) ;logical DOS sector of root directory
DATAsector dw 1 DUP (?) ;logical DOS sector of data start
BytesCluster dw 1 DUP (?) ;bytes per cluster
LOGSEC dd 1 DUP (?) ;logical DOS sector (32-bit)
DOScylinder dw 1 DUP (?) ;format for IOCTL Read Track
DOShead dw 1 DUP (?) ; "
DOSsector dw 1 DUP (?) ; "
lo dw 1 DUP (?) ;Quiksort data
hi dw 1 DUP (?)
reclen dw 1 DUP (?)
cstart dw 1 DUP (?)
cbytes db 1 DUP (?)
db 1 DUP (?) ;even it up
sptr dw 1 DUP (?)
Swap1 dw 1 DUP (?) ;->start of record to swap
Swap2 dw 1 DUP (?) ;->start of record to swap
TmpReg dw 1 DUP (?)
rBlock rwBlock <> ;IOCTL read track info
wBlock rwBlock <> ;IOCTL write track info
BuffDeviceParms DeviceParms <> ;device parameters
EVEN
BuffDirSort DirEntry 1+MAXDIR+1 DUP (<>) ;directory entry slots (@#$!)
;1 first for Quiksort work space
;1 extra for count check
.DATA
IDmsg db 'SORTDIR 1.02 (C) 1991 Cornel Huth - All Rights Reserved',13,10
IDmsgL =$-IDmsg
CRLF db 13,10
CurrDrvMsgPre db 'Sorting '
CurrDrvMsg db 'Z:\'
CurrDrvMsgPreL =$-CurrDrvMsgPre
MSortInfo db 'Entries skipped/sorted ' ;sorted excludes deleted entries
SortInfo db 9 DUP (' ') ;max 4 +'/'+ 4
MSortInfoL =$-MSortInfo
EDoneNo =0
EDone db 'ok'
EDoneL =$-EDone
EDOSNo =1
MinDOS EQU 0314h
EDOS db 'Requires DOS 3.20+'
EDOSL =$-EDOS
db '$' ;for DOS 1 message
EUnkSwitchNo =2
EUnkSwitch db '* Invalid switch. Use: C>sd [/<en>]',13,10,13,10
db 9,'On current drive/directory sort directory by:',13,10
db 9,'/e ext.filename (default)',13,10 ;B3*
db 9,'/n filename.ext',13,10
EUnkSwitchL =$-EUnkSwitch
EInvalidDrvNo =3
EInvalidDrv db 'Invalid drive' ;remote drive
EInvalidDrvL =$-EInvalidDrv
EAccessNo =4
EAccess db 'Cannot access media' ;r/w fault
EAccessL =$-EAccess
EUnkDeviceNo =5
EUnkDevice db 'Unknown DOS device' ;e.g., 8-in floppy
EUnkDeviceL =$-EUnkDevice
ERootFarNo =6
ERootFar db 'Root directory not within first 64K DOS sectors'
ERootFarL =$-ERootFar
EInvalidFuncNo =7
EInvalidFunc db 'Program function not available' ;stub message
EInvalidFuncL =$-EInvalidFunc
ENoFATmemoryNo =8
ENoFATmemory db 'Not enough memory for FAT'
ENoFATmemoryL =$-ENoFATmemory
EFATnoMatchNo =9
EFATnoMatch db 'File Allocation Tables do not match'
EFATnoMatchL =$-EFATnoMatch
EInvalidDTANo =10
EInvalidDTA db 'Unknown DOS DTA structure';CDS not 100% compat in DRDOS-5
EInvalidDTAL =$-EInvalidDTA ;so use DTA structure after FindF
EOS2No =11 ;to locate starting cluster of SD
EOS2 db 'Cannot operate in OS/2 DOS box'
EOS2L =$-EOS2
EMathNo =12
EMath db 'Math overflow'
EMathL =$-EMath
EFATlinkNo =13
EFATlink db 'Too many file entries or FAT link corrupt' ;less harsh
EFATlinkL =$-EFATlink
EVEN
ErrMsgW dw EDone,EDOS,EUnkSwitch,EInvalidDrv,EAccess,EUnkDevice
dw ERootFar,EInvalidFunc,ENoFATmemory,EFATnoMatch,EInvalidDTA
dw EOS2,EMath,EFATLink
ErrMsgL db EDoneL,EDOSL,EUnkSwitchL,EInvalidDrvL,EAccessL,EUnkDeviceL
db ERootFarL,EInvalidFuncL,ENoFATmemoryL,EFATnoMatchL,EInvalidDTAL
db EOS2L,EMathL,EFATLinkL
ValidDevices db 0,1,2,5,7,8 ;320/360,1.2,720,HD,1.44,2.88
ValidDevicesL =$-ValidDevices ;device types handled
SortOptions db 'EN' ;B3* options
SortOptionsL =$-SortOptions
SortOrder db 'E'
ThisDir db '.',0 ;THIS subdirectory filename
Trap00 db 0 ;=1 then INT00 has been revectored
Trap1B db 0 ;=1 then INT1B has been revectored
Trap23 db 0 ;=1 then INT23 has been revectored
Trap24 db 0 ;=1 then INT24 has been revectored
.CODE
Bail: sub bh,bh
push bx ;bail to DOS w/message and exitcode
sub ch,ch
mov cl,[bx+ErrMsgL]
shl bl,1
mov dx,[bx+ErrMsgW]
mov bx,STDOUT
mov ah,40h
int 21h
sub bl,bl
cmp bl,Trap1B ;changed INT1B vector?
je @F ;no
call INT1Bswitch ;yes,restore (INT23/24 restored by DOS)
@@: sub bl,bl
cmp bl,Trap00 ;changed INT00 vector?
je @F ;no
call INT00switch ;yes,restore
@@: pop ax
mov ah,4Ch
int 21h
;-----------------------
BailDOS1: mov dx,OFFSET EDOS ;bail back to DOS 1
mov ah,9
int 21h
retf
;=======================
Start: push ds ;B1* DOS 1 exit return PSP:0
sub ax,ax
push ax
mov ax,DGROUP
mov ds,ax
mov bx,es
mov PSPseg,bx
mov es,ax
cli
mov ss,ax
mov sp,OFFSET STACK
sti ;ds=es=ss=DGROUP
ASSUME ds:DGROUP,es:DGROUP,ss:DGROUP
;-----------------------CHECK DOS VERSION
mov ah,30h
int 21h
cmp al,2
jb BailDOS1 ;DOS 1 bail
mov MajorV,al
mov MinorV,ah
cmp al,HIGH MinDOS
mov bl,EDOSNo ;error message number
ja @F ;major above min
jb Bail ;major below min
cmp ah,LOW MinDOS
jb Bail ;minor below min
@@: ;-----------------------SHOW PROGRAM ID
ID01: mov dx,OFFSET IDmsg
mov cx,IDmsgL
mov bx,STDOUT
mov ah,40h
int 21h
cmp MajorV,10h ;OS/2 DOS box?
jb @F ;no
mov bl,EOS2No
jmp Bail
@@: ;-----------------------DRIVE RESET
DR01: mov ah,0Dh
int 21h
@@: ;-----------------------CHECK COMMAND LINE PARMS
CL01: mov si,80h
mov ds,PSPseg ;ds=PSP
cld
lodsb
or al,al ;anything?
jz CL04 ;no
CL02: lodsb
cmp al,13 ;CR then done
je CL04
cmp al,32 ;skip anything space or below
jbe CL02
cmp al,'/' ;option must lead with slash
jne CL03
lodsb ;we expect only 1 character
and al,255-32 ;upper case it
mov cx,es ;load ds=DGROUP
mov ds,cx
mov di,OFFSET SortOptions
mov cx,SortOptionsL
repne scasb ;repeat until found or not
mov SortOrder,al ;use upper case
je @F ;found
CL03: mov cx,es ;load ds=DGROUP on bad switch leader
mov ds,cx
mov bl,EUnkSwitchNo
jmp Bail
CL04: mov ax,es ;load ds=DGROUP on no parms
mov ds,ax
;@@: ;-----------------------VECTOR INT24 TO LOCAL HANDLER
; ;Not used, let COMMAND query what to do since INT24 will occur
; ;only using the non-IOCTL (which are used only to read drive)
; ;INT1B/00 vectors not changed until after the non-IOCTL reads
;INT24trap: mov bl,1
; call INT24switch ;DOS restores on exit
@@: ;-----------------------VECTOR INT23 TO LOCAL HANDLER
INT23trap: mov bl,1
call INT23switch ;DOS restores on exit
@@: ;-----------------------GET DEFAULT DRIVE
GetDrv: mov ah,19h
int 21h
inc ax ;0=A,1=B,2=C,...
mov CurrDrive,al ;1=A,2=B,3=C,...
@@: ;-----------------------IS DRIVE REMOTE
ChkRemote: mov bl,CurrDrive
mov ax,4409h
int 21h
test dx,1000h ;bit 12 drive is remote
jz @F ;local drive
mov bl,EInvalidDrvNo
jmp Bail
@@: ;-----------------------GET CURRENT DIRECTORY
GetDir: mov dl,CurrDrive
mov si,OFFSET CurrDir
mov ah,47h
int 21h
@@: ;-----------------------GET STARTING CLUSTER OF SUBDIR
GetStartClust: mov al,CurrDir
or al,al ;root?
jz @F ;yes,nevermind
mov cx,10h ;look for "."
mov dx,OFFSET ThisDir
mov ah,4Eh ;find first file
int 21h
push es
mov es,PSPseg
mov ax,es:[81h] ;get first two characters of template
cmp ax,' .' ;should be dot-space, inteled
mov ax,es:[8Fh] ;cluster number
pop es
jne GetStartClust01 ;was not dot-space
mov StartCluster,ax
jmp SHORT @F
GetStartClust01:mov bl,EInvalidDTANo
jmp Bail
@@: ;-----------------------VECTOR INT1B TO LOCAL HANDLER
INT1Btrap: mov bl,1
call INT1Bswitch ;this must be restored before exiting
@@: ;-----------------------VECTOR INT00 TO LOCAL HANDLER
INT00trap: mov bl,1
call INT00switch ;this must be restored before exiting
@@: ;-----------------------GET DEVICE PARMS
GetDeviceParms: mov bl,CurrDrive
sub bh,bh
mov cx,0860h
mov BuffDeviceParms.dpSpecFunc,1 ;get curr medium info
mov dx,OFFSET BuffDeviceParms
mov ax,440Dh
int 21h
jnc @F
mov bl,EAccessNo
jmp Bail
@@: ;-----------------------IS DEVICE KNOWN
ChkDevice: mov al,BuffDeviceParms.dpDevType
mov di,OFFSET ValidDevices
mov cx,ValidDevicesL
repne scasb
je @F ;can handle device
mov bl,EUnkDeviceNo
jmp Bail
@@: cmp WPTR BuffDeviceParms.dpHiddenSecs+2,0
je @F
mov bl,ERootFarNo ;root dir not in first 64K DOS sectors
jmp Bail
@@: ;-----------------------CALC FAT/ROOT/DATA SECTOR START
GetBase: mov ax,BuffDeviceParms.dpResSectors
add ax,WPTR BuffDeviceParms.dpHiddenSecs
jc GetBase01
mov bx,ax
mov FATsector,ax
mov al,BuffDeviceParms.dpFATs
sub ah,ah
mul BuffDeviceParms.dpFATsecs
jc GetBase01
add ax,bx
jc GetBase01
mov ROOTsector,ax
mov ax,BuffDeviceParms.dpRootDirEnts
mov cx,32
mul cx
div BuffDeviceParms.dpBytesSector
mov dx,ROOTsector
add ax,dx
mov DATAsector,ax
mov ax,BuffDeviceParms.dpBytesSector
mov dl,BuffDeviceParms.dpSectorsClust
sub dh,dh
mul dx
jc GetBase01
mov BytesCluster,ax
jmp SHORT @F
GetBase01: mov bl,ERootFarNo ;root dir not in first 64K DOS sectors
jmp Bail
@@: ;-----------------------CLEAR DIR SORT BUFFER
ClearSortBuff: sub ax,ax
mov cx,SIZE BuffDirSort/2
mov di,OFFSET BuffDirSort
rep stosw
@@: ;-----------------------DETERMINE SORT TYPE
SortWhatDir: call ShowDrvInfo
call ShowDirInfo
call OutputCRLF
mov al,CurrDir
or al,al ;root?
jz @F ;yes
jmp SHORT SortSubDir
@@: ;-----------------------SORT ROOT DIRECTORY
SortRootDir: mov ax,BuffDeviceParms.dpRootDirEnts
mov cx,32
mul cx
div BuffDeviceParms.dpBytesSector
mov cx,ax ;cx=root dir sectors
mov ax,ROOTsector
sub dx,dx ;dx:ax=first DOS sector
mov di,OFFSET BuffDirSort+32 ;es:di->buffer
call ReadDOSsectors
call CountUsedEnts ;cx=entries to sort,dx=last HSD entry
mov bp,di ;di=deleted entries (still sorted)
push cx ;save entries to sort
push dx ;save entries skipped
push cx ;and entries to sort again
mov di,OFFSET SortInfo
mov ax,dx
sub dx,dx
call Hex2ASCII
dec di ;backup over Z
mov al,'/' ;es:di->next slot in output buffer
stosb
pop ax ;get entries to sort
sub ax,bp ;deleted entries not counted in list
sub dx,dx
call Hex2ASCII
pop dx ;get 'em back
pop cx
cmp cx,1 ;0 or 1 entries?
jbe @F ;yes
inc dx ;dx=first entry to start sort at
add cx,dx ;A1*last item position+1
dec cx ;A1*last item position
call QuiksortFN
sub ax,ax
sub dx,dx ;use same parms as read
call WriteDOSsectors
@@: call ShowSortInfo
call OutputCRLF
sub bl,bl ;done okay
jmp Bail
@@: ;-----------------------SORT SUBDIRECTORY
SortSubDir:
@@: ;-----------------------ALLOCATE, LOAD (& COMPARE) FAT(S) BUFFER
AllocReadFAT: mov ax,BuffDeviceParms.dpFATsecs
mul BuffDeviceParms.dpBytesSector
jc AllocReadFAT01 ;FAT > 64K-1
mov bp,ax ;save bytes needed for FAT buffer
mov cl,4
shr ax,cl ;get paras needed for FAT
mov bx,ax
mov ah,48h
int 21h
jc AllocReadFAT01 ;not enough memory
mov SegBuffFAT,ax ;segment of FAT buffer
cmp BuffDeviceParms.dpFATs,1
je @F ;only 1 FAT
mov ah,48h ;get buffer for FAT2
int 21h
jc AllocReadFAT01 ;not enough memory
mov SegBuffFAT2,ax ;segment of FAT2 buffer
sub di,di ;load FAT2
mov es,ax ;es:di->FAT2 buffer
mov ax,FATsector
add ax,BuffDeviceParms.dpFATsecs
sub dx,dx ;dx:ax=first FAT2 sector
mov cx,BuffDeviceParms.dpFATsecs ;sectors to read
call ReadDOSsectors
@@: sub di,di ;load FAT
mov es,SegBuffFAT ;es:di->FAT buffer
mov ax,FATsector
sub dx,dx ;dx:ax=first FAT sector
mov cx,BuffDeviceParms.dpFATsecs ;sectors to read
call ReadDOSsectors
cmp BuffDeviceParms.dpFATs,1
je @F ;can't compare if only 1 FAT
mov dx,ds ;save ds in dx for a sec
sub si,si
sub di,di
mov es,SegBuffFAT2
mov ds,SegBuffFAT
mov cx,bp
shr cx,1 ;compare words
repe cmpsw
jne AllocReadFAT02 ;FATs do not match
mov ah,49h ;deallocate FAT 2 buffer
int 21h
mov ds,dx ;restore seg regs
mov es,dx
jmp SHORT @F
AllocReadFAT01: mov bl,ENoFATmemoryNo
jmp Bail
AllocReadFAT02: mov ds,dx ;restore seg regs
mov es,dx
mov bl,EFATnoMatchNo
jmp Bail
@@: ;-----------------------GET ALL CLUSTERS ASSIGNED TO THIS SUBDIR
FATtruckin: mov FATtype,16
mov ax,BuffDeviceParms.dpSectors
or ax,ax ;huge part?
jz @F ;yes
sub dx,dx
sub bh,bh
mov bl,BuffDeviceParms.dpSectorsClust
div bx ;ax=clusters on drive
cmp ax,4087 ;4087+ uses 16-bit FAT
jae @F
mov FATtype,12 ;else a 12-bit FAT
@@: mov cx,32 ;B2*determine how many clusters the
mov ax,MAXDIR ;directory entry buffer is
mul cx ;ax=MAXDIR*32=bytes available
div BytesCluster ;ax=clusters available
mov cx,ax ;count actual clusters available
jcxz @F ;B2* buff not large enough for 1 cluster
push ds
mov ds,SegBuffFAT ;ds:si->FAT (si set in FollowFAT1x)
mov di,OFFSET ClusterList
mov ax,es:StartCluster ;es:di->ClusterList array
FATtruckin01: stosw ;put links--
cmp es:FATtype,12 ;doing a 12-bit FAT?
jne FATtruckin02 ;no
call FollowFAT12 ;yes
jmp SHORT FATtruckin03
FATtruckin02: call FollowFAT16 ;16-bit FAT
FATtruckin03: or ax,ax ;0 then at end of link
jz FATtruckin04
loop FATtruckin01
pop ds ;ds=DGROUP
@@: mov bl,EFATlinkNo ;too many clusters for buffer
jmp Bail
FATtruckin04: stosw ;0 demarks end of ClusterList
pop ds ;ds=DGROUP
@@: ;-----------------------READ SUBDIR CLUSTERS
ReadSubDirClust:mov si,OFFSET ClusterList ;ds:si->ClusterList array
mov bl,BuffDeviceParms.dpSectorsClust
sub bh,bh ;bx=sectors/cluster (sectors to read)
mov cx,bx ;cx=sectors to read
mov di,OFFSET BuffDirSort+32 ;es:di=>dir sort buffer
@@: lodsw ;get a cluster from list
or ax,ax ;done?
jz SortSD01 ;yes
dec ax ;no,convert cluster to DOS LOGSEC
dec ax ;subtract 2...
mul bx ;times sectors/cluster=DOS data sector
add ax,DATAsector ;add in relative data start sector
adc dx,0 ;dx:ax=32-bit sector number
push bx ;save multiplier
push cx ;save sector read count
push di ;save buffer address
call ReadDOSsectors ;read cluster's sectors to buffer
pop di
pop cx
pop bx
add di,BytesCluster
jmp @B
@@: ;-----------------------SORT SUBDIR BUFFER
SortSD01: mov di,OFFSET BuffDirSort+32 ;es:di->buffer
call CountUsedEnts ;cx=entries to sort,dx=last HSD entry
mov bp,di ;di=deleted entries (still sorted)
push cx ;save entries to sort
push dx ;save entries skipped
push cx ;and entries to sort again
mov di,OFFSET SortInfo
mov ax,dx
sub dx,dx
call Hex2ASCII
dec di ;backup over Z
mov al,'/' ;es:di->next slot in output buffer
stosb
pop ax ;get entries to sort
sub ax,bp ;deleted entries not counted in list
sub dx,dx
call Hex2ASCII
pop dx ;get 'em back
pop cx
cmp cx,1 ;0 or 1 entries?
jbe SkipSort ;yes
inc dx ;dx=first entry to start sort at
add cx,dx ;A1*last item position+1
dec cx ;A1*last item position
call QuiksortFN
@@: ;-----------------------WRITE SUBDIR CLUSTERS
WriteSubDirClust:mov si,OFFSET ClusterList ;ds:si->ClusterList array
mov bl,BuffDeviceParms.dpSectorsClust
sub bh,bh ;bx=sectors/cluster (sectors to read)
mov cx,bx ;cx=sectors to read
mov di,OFFSET BuffDirSort+32 ;es:di=>dir sort buffer
@@: lodsw ;get a cluster from list
or ax,ax ;done?
jz @F ;yes
dec ax ;no,convert cluster to DOS LOGSEC
dec ax ;subtract 2...
mul bx ;times sectors/cluster=DOS data sector
add ax,DATAsector ;add in relative data start sector
adc dx,0 ;dx:ax=32-bit sector number
push bx ;save multiplier
push cx ;save sector read count
push di ;save buffer address
call WriteDOSsectors ;write cluster's sectors to buffer
pop di
pop cx
pop bx
add di,BytesCluster
jmp @B
@@:
SkipSort: call ShowSortInfo
call OutputCRLF
@@: ;-----------------------DONE
AllDone: mov ah,0Dh ;drive reset
int 21h
sub bl,bl
jmp Bail
;=======================
;SUBROUTINES
;-----------------------FOLLOW FAT12 CHAIN
;USES: ax,bx,dx,si RET: ax=next cluster,=0 if last link
FollowFAT12: test ax,1 ;FAT entry number odd?
pushf ;save for a sec
mov bx,3 ;determine if last link
mul bx ;dx:ax=Link * 3
shr dx,1
rcr ax,1 ;dx:ax=Link * 1.5
mov si,ax
mov ax,[si] ;get next cluster
popf
jnz @F ;yes odd
and ax,0FFFh ;even link use right 12 bits
jmp SHORT FollowFAT1201
@@: shr ax,1 ;odd link use left 12 bits
shr ax,1
shr ax,1
shr ax,1
FollowFAT1201: cmp ax,0FF8h ;end link?
jb @F ;no
sub ax,ax ;yes,return 0
@@: retn ;return cluster number
;-----------------------FOLLOW FAT16 CHAIN
;USES: ax,si RET: ax=next cluster,=0 if last in link
FollowFAT16: shl ax,1 ;ax=ax*2
mov si,ax
mov ax,[si] ;get link word
cmp ax,0FFF8h ;end link?
jb @F ;no
sub ax,ax ;yes,return 0
@@: retn ;return cluster number
;-----------------------CONV DOS LOGICAL SECTOR TO CYL/HD/SEC
;USES: ax,cx,dx RET: DOScylinder,DOShead,DOSsector
ConvLOGSEC: mov ax,BuffDeviceParms.dpSectorsTrack
mul BuffDeviceParms.dpHeads
mov cx,ax ;cx=CylSec,sectors on cylinder
mov ax,WPTR LogSec
mov dx,WPTR LogSec+2 ;dx:ax=32-bit DOS sector
div cx ;ax=cyl,cylinder of DOS sector
mov DOScylinder,ax
mul cx ;dx:ax=cyl*CylSec
sub ax,WPTR LogSec
sbb dx,WPTR LogSec+2
not dx ;negate
neg ax
sbb dx,-1 ;dx:ax=32-bit sector offset (dx=0)
mov cx,ax ;cx=rm,sectors into this DOS cylinder
div BuffDeviceParms.dpSectorsTrack
mov DOShead,ax
mul BuffDeviceParms.dpSectorsTrack
sub cx,ax
mov DOSsector,cx
retn
;-----------------------ZERO BuffDirSort
;USES: ax,cx,di
ZeroBuffDirSort:sub ax,ax
mov cx,(MAXDIR+1)*32/2
mov di,OFFSET BuffDirSort
rep stosw
retn
;-----------------------COUNT DIRECTORY ENTRIES TO SORT
;USES: ax,bx,si,di RET: cx,dx,di FIND LAST H/S/D ENTRY & DEL#
CountUsedEnts: mov si,OFFSET BuffDirSort+32
sub cx,cx ;track entries to sort
mov dx,cx ;track last HSD entry
mov di,cx ;track deleted entries
mov bx,31
@@: lodsb ;first byte of filename (0=unused entry)
or al,al ;B4* unused?
jz CountUsedEnts3 ;B4*
inc cx ;B4* used entry count
mov ah,[si+10] ;attribute (si incremented by lodsb)
test ah,16h ;system,hidden,subdir entry?
jz CountUsedEnts1 ;no
cmp al,0E5h ;erased system,hidden,subdir entry?
je CountUsedEnts1 ;yes
mov dx,cx ;current max hidden/system entry
sub di,di ;zero deleted entries not skipped
CountUsedEnts1: cmp al,0E5h ;track number of deleted entries
jne CountUsedEnts2
inc di
CountUsedEnts2: add si,bx
jmp @B
CountUsedEnts3: sub cx,dx ;cx=directory entries to sort
retn ;dx=last hidden/system/subdir entry or 0
;di=deleted entries not skipped
;-----------------------OUTPUT CR/LF
;USES: ah,bx,cx,dx
OutputCRLF: mov dx,OFFSET CRLF
mov cx,2
mov bx,STDOUT
mov ah,40h
int 21h
retn
;-----------------------SHOW DRIVE BEING SORTED
;USES: ax,bx,cx,dx
ShowDrvInfo: mov al,CurrDrive
add al,'@'
mov CurrDrvMsg,al
mov dx,OFFSET CurrDrvMsgPre
mov cx,CurrDrvMsgPreL
mov bx,STDOUT
mov ah,40h
int 21h
retn
;-----------------------SHOW DIRECTORY BEING SORTED
;USES: ax,bx,cx,dx,di
ShowDirInfo: mov cx,40h ;max dir length
mov di,OFFSET CurrDir
sub al,al
repne scasb
sub cx,40h
neg cx
dec cx
jcxz @F
mov dx,OFFSET CurrDir
mov bx,STDOUT
mov ah,40h
int 21h
@@: retn
;-----------------------SHOW SORT INFO
;USES: ah,bx,cx,dx
ShowSortInfo: mov dx,OFFSET MSortInfo
mov cx,MSortInfoL
mov bx,STDOUT
mov ah,40h
int 21h
@@: retn
;-----------------------READ TRACK ON LOGICAL DRIVE
;USES: ax,bx,cx,dx RET: NC=okay CY=error in ax
ReadTrack: mov bl,CurrDrive
sub bh,bh
mov cx,0861h ;device category/read track
mov dx,OFFSET rBlock ;read block structure
mov ax,440Dh
int 21h
retn ;carry set on error/ax=1,2,5
;-----------------------WRITE TRACK ON LOGICAL DRIVE
;USES: ax,bx,cx,dx RET: NC=okay CY=error in ax
WriteTrack: mov bl,CurrDrive
sub bh,bh
mov cx,0841h ;device category/write track
mov dx,OFFSET wBlock ;write block structure
mov ax,440Dh
int 21h
retn ;carry set on error/ax=1,2,5
;-----------------------READ CX DOS SECTORS AT DX:AX TO ES:DI
;USES: ax,cx,dx (CONSECUTIVE PHYSICAL SECTORS)
ReadDOSsectors: mov WPTR LOGSEC,ax
mov WPTR LOGSEC+2,dx
sub ax,ax
mov rBlock.rwSpecFunc,al
mov wBlock.rwSpecFunc,al ;load write block too
push cx
call ConvLOGSEC
pop cx
mov ax,DOShead
mov rBlock.rwHead,ax
mov wBlock.rwHead,ax
mov ax,DOScylinder
mov rBlock.rwCylinder,ax
mov wBlock.rwCylinder,ax
mov ax,DOSsector
mov rBlock.rwFirstSector,ax
mov wBlock.rwFirstSector,ax
mov rBlock.rwSectors,cx
mov wBlock.rwSectors,cx
mov WPTR rBlock.rwBuffer,di
mov WPTR rBlock.rwBuffer+2,es
mov WPTR wBlock.rwBuffer,di
mov WPTR wBlock.rwBuffer+2,es
call ReadTrack
jnc @F
mov bl,EAccessNo
jmp Bail
@@: retn
;-----------------------WRITE CX DOS SECTORS AT DX:AX FROM ES:DI
;USES: ax,cx,dx (CONSECUTIVE PHYSICAL SECTORS)
WriteDOSsectors:or ax,ax ;use same info as last read?
jnz @F ;no
or dx,dx
jz WriteSame ;yes, use last read's parms
@@: mov WPTR LOGSEC,ax
mov WPTR LOGSEC+2,dx
sub ax,ax
mov wBlock.rwSpecFunc,al
push cx
call ConvLOGSEC
pop cx
mov ax,DOShead
mov wBlock.rwHead,ax
mov ax,DOScylinder
mov wBlock.rwCylinder,ax
mov ax,DOSsector
mov wBlock.rwFirstSector,ax
mov wBlock.rwSectors,cx
mov WPTR wBlock.rwBuffer,di
mov WPTR wBlock.rwBuffer+2,es
WriteSame: call WriteTrack
jnc @F
mov bl,EAccessNo
jmp Bail
@@: retn
;-----------------------OUTPUT DX:AX IN ASCII TO ES:DI
;USES: ax,bx,cx,dx,si,di RET: di->next slot,ASCII output @ ES:DI
Hex2ASCII: mov si,10 ;base
mov bx,ax
mov cx,dx
mov dx,-1 ;conv digits stored on stack after -1
push dx
Hex2ASCII01: xchg ax,cx ;ax=high word
sub dx,dx
div si
xchg cx,ax ;cx=high divide
xchg ax,bx ;ax=low word,dx=remainder
div si
xchg bx,ax ;bx=low divide
add dl,'0' ;make ASCII
push dx ;save 'em
or bx,bx ;more left to divide?
jne Hex2ASCII01 ;yes
or cx,cx
jne Hex2ASCII01 ;yes
mov bl,'0' ;in case dx:ax=0 and leading zero flag
Hex2ASCII02: pop dx ;get 'em
cmp dx,-1 ;all done?
je Hex2ASCII04 ;yes
or bl,dl ;set bl to indicate leading '0' or not
cmp bl,'0' ;still a leading zero?
je @F ;yes,skip it
mov al,dl
stosb
@@: jmp SHORT Hex2ASCII02
Hex2ASCII04: cmp bl,'0' ;dx:ax=0?
jne @F ;no
mov al,bl
stosb
@@: sub al,al ;zero terminate it
stosb
retn
COMMENT ~ Not needed, see above
;-----------------------TRAP INT24
;USES: none
INT24switch: push es
push ds
push dx
push ax
mov Trap24,bl
or bl,bl ;trap or restore?
jz INT24s2 ;0=restore
mov INT24error,0
mov ax,3524h
int 21h
mov INT24seg,es
mov INT24off,bx
mov ax,2524h
mov dx,OFFSET INT24handler
push cs
pop ds
INT24s1: int 21h
pop ax
pop dx
pop ds
pop es
retn
INT24s2: mov ax,2524h
mov dx,INT24off
mov ds,INT24seg
jmp INT24s1
INT24handler: sti ;INT24 HANDLER
add sp,6
mov ax,di
sub ah,ah
add ax,13h
mov ss:INT24error,ax
pop ax
pop bx
pop cx
pop dx
pop si
pop di
pop bp
pop ds
pop es
iret
END COMMENT ~
;-----------------------TRAP INT23
;USES: none
INT23switch: push es
push ds
push dx
push ax
mov Trap23,bl
or bl,bl ;trap or restore?
jz INT23s2 ;0=restore
mov ax,3523h
int 21h
mov INT23seg,es
mov INT23off,bx
mov ax,2523h
mov dx,OFFSET INT23handler
push cs
pop ds
INT23s1: int 21h
pop ax
pop dx
pop ds
pop es
retn
INT23s2: mov ax,2523h
mov dx,INT23off
mov ds,INT23seg
jmp INT23s1
INT23handler: iret ;INT23 HANDLER
;-----------------------TRAP INT1B
;USES: none
INT1Bswitch: push es
push ds
push dx
push ax
mov Trap1B,bl
or bl,bl ;trap or restore?
jz INT1Bs2 ;0=restore
mov ax,351Bh
int 21h
mov INT1Bseg,es
mov INT1Boff,bx
mov ax,251Bh
mov dx,OFFSET INT1Bhandler
push cs
pop ds
INT1Bs1: int 21h
pop ax
pop dx
pop ds
pop es
retn
INT1Bs2: mov ax,251Bh
mov dx,INT1Boff
mov ds,INT1Bseg
jmp INT1Bs1
INT1Bhandler: push ax ;INT1B HANDLER
mov al,20h
out 20h,al
pop ax
iret
;-----------------------TRAP INT00
;USES: none
INT00switch: push es
push ds
push dx
push ax
mov Trap00,bl
or bl,bl ;trap or restore?
jz INT00s2 ;0=restore
mov ax,3500h
int 21h
mov INT00seg,es
mov INT00off,bx
mov ax,2500h
mov dx,OFFSET INT00handler
push cs
pop ds
INT00s1: int 21h
pop ax
pop dx
pop ds
pop es
retn
INT00s2: mov ax,2500h
mov dx,INT00off
mov ds,INT00seg
jmp INT00s1
INT00handler: add sp,6 ;remove iret junk
mov bl,EMathNo ;INT00 HANDLER
jmp Bail
;-----------------------SORT DIRSORT BUFFER BY FILENAME/EXT
;Use your own sort routine
;if SortMode='@' or 'N' sort by filename, if 'E' then extension
;dir entries start at BuffDirSort+32
;with cx=last entry to sort dx=entry to start sort at
QuiksortFN: mov bl,EInvalidFuncNo
jmp Bail
END Start